(function($, gmwk) {

   /**
    * @class Contact CRUD
    * @constructor
    * @member gmwk.classes
    */
    function Contact(Options) {
    
        var self = this;
        var sClassName = Options.sClassName;
        var jqContainer = Options.jqObjectContainer;
        var jqTemplates = jqContainer.find(".Contact_template");
        var jqList = jqContainer.find(".Contact_list");
        var jqForm = jqContainer.find(".Contact_form");
        var fListTemplate;
        var fFormTemplate;
        
        // Bind click event on object container
        jqContainer.click(fClick);
        
        //console.info("---------> Contact constructed");
        
        /**
         * Get the name of this class
         * @public
         * @returns {String} Class name
         */
        this.getClassName = function() {
            return sClassName;
        }
        
        /**
         * Required route function
         * @param {Object} Fragment URL fragment object
         * @public
         */
        this.route = function(Fragment) {
            // Default action is list
            if (Fragment.a === undefined) {
                fList();
            // Do action
            } else {
                switch (Fragment.a) {
                  case "list":
                      fList();
                      break;
                  case "add":
                      fAdd();
                      break;
                  case "edit":
                      fEdit(Fragment.nCID);
                      break;
                  case "delete":
                      fDelete(Fragment.nCID);
                      break;
                }
            }
        }

        /**
         * Click event handler
         * @param {Object} e Click event object
         * @private
         * @returns {Undefined}
         */
        function fClick(e) {
            var jqTarget = $(e.target);
            // If the closest object container does not match this class container do nothing
            if (gmwk.closestObjectContainer(jqTarget) != jqContainer.attr("id")) {
                return;
            }
            // Edit
            if (
                jqTarget.closest("div").is(".Contact_list_row") &&
                jqTarget.is(":not(.Contact_delete)")
            ) {
                fLoad(
                  {
                      a: "edit",
                      nCID: fGetCID(jqTarget.closest(".Contact_list_row"))
                  }
                );
            // Save
            } else if (jqTarget.is(".Contact_save")) {
                fSave();
            }
        }
        
        /**
         * Get contact ID
         * @param {jQuery} jqListRow Contact list row container
         * @private
         * @returns {String} Contact ID
         */
        function fGetCID(jqListRow) {
            return jqListRow.find(".Contact_nCID").text();
        }
        
        /**
         * Load an action, Options will override current fragment state.
         *    Hashchange will cause Router to call self.route with Options 
         * @param {Object} Options Options will be passed to self.route
         * @param {Number} [nMode=gmwk.Router.PARAMS_OVERRIDE_STATE]
         * @private
         */
        function fLoad(Options, nMode) {
            if (typeof nMode == undefined) {
              nMode = gmwk.Router.PARAMS_OVERRIDE_STATE;
            }
            gmwk.Router.load(
                $.extend(
                    {
                        l: "Dashboard",
                        p: "Contact"
                    },
                    Options
                ),
                nMode
            );
        }
        
        /**
         * List contacts
         * @private
         */
        function fList() {
            fToggleSubMenu("list");
            gmwk.API.request(
                "Contact/list",
                {},
                function(Data) {
                    fRenderList(Data);
                }
            );
        }

        /**
         * Edit a contact
         * @param {Number} nCID Contact ID
         * @private
         */        
        function fEdit(nCID) {
            fToggleSubMenu("edit");
            if (
                (typeof nCID === "undefined") ||
                (nCID === "")
            ) {
                alert("Cannot edit, missing nCID");
                return;
            }
            gmwk.API.request(
                "Contact/details",
                {
                    Params: {
                        nCID: nCID
                    }
                },
                function(Data) {
                    fRenderForm(Data);
                }
            );
        }

        /**
         * Add a contact
         * @private
         */
        function fAdd() {
            fToggleSubMenu("add");
            fRenderForm(
                {
                    aContact: [
                        {
                            nCID: 0,
                            sName: "",
                            sLastName: ""
                        }
                    ]
                }
            );
        }

        /**
         * Delete a contact
         * @param {Number} nCID Contact ID
         * @private
         */
        function fDelete(nCID) {
            if (
                (typeof nCID === "undefined") ||
                (nCID === "")
            ) {
                alert("Cannot delete, missing nCID");
                return;
            }
            gmwk.API.request(
                "Contact/delete",
                {
                    Params: {
                        nCID: nCID
                    }
                },
                function(Data) {
                    fLoad({a: "list"}, gmwk.Router.PARAMS_REPLACE_STATE);
                }
            );
        }

        /**
         * Save contact
         * @private
         */
        function fSave() {
            gmwk.API.request(
                "Contact/save",
                {
                    jqForm: jqForm.find("form")
                },
                function(Data) {
                    fLoad({a: "list"});
                }
            );
        }
        
        /**
         * Toggle selected submenu item
         *    TODO: This function should be in a shared library 
         * @param {String} sSubMenu Sub menu description
         * @private
         */
        function fToggleSubMenu(sSubMenu) {
            jqContainer.find(".Contact_menu_item").removeClass("global_submenu_on");
            jqContainer.find(".Contact_menu_item.Contact_" + sSubMenu).addClass("global_submenu_on");
        }
        
        /**
         * Generate contact list with PURE templating engine and show it
         * @param {Object} Data Contact list data
         * @private
         */
        function fRenderList(Data) {
            var Directive = {
                "div.Contact_list_row": { // Find ul with class Contact_list_row
                    "Contact<-aContacts": { // Iterate Contact over array aContact
                        "span.Contact_nCID": "Contact.nCID",
                        // Assign value of Contact.sName to li with class Contact_sName
                        "span.Contact_sName": "Contact.sName",
                        "span.Contact_sLastName": "Contact.sLastName",
                        // Assign return value of function to href property
                        "a.Contact_delete@href": function(Options) {
                            return "#l=Dashboard&p=Contact&a=delete&nCID=" + Options.item.nCID;
                        }
                    }
                }
            }
            // Compile the template to make it re-useable
            if (typeof fListTemplate == "undefined") {
                fListTemplate = jqList.find(".Contact_list_template")
                    .compile(Directive);
            }
            // Render
            jqList.find(".Contact_list_template")
                .render(Data, fListTemplate);
            // Hide other templates and show list
            jqTemplates.hide();
            jqList.show();
        }

        /**
         * Generate contact form with PURE templating engine and show it
         * @param {Object} Data Individual contact data
         * @private
         */        
        function fRenderForm(Data) {
            var Contact = Data.aContact[0];
            var Directive = {
                ".Contact_nCID@value": "nCID",
                ".Contact_sName@value": "sName",
                ".Contact_sLastName@value": "sLastName"
            }
            // Compile the template
            if (typeof fFormTemplate == "undefined") {
                fFormTemplate = jqForm.find(".Contact_form_template")
                    .compile(Directive);
            }
            // Render
            jqForm.find(".Contact_form_template")
                .render(Contact, fFormTemplate);
            // Hide other templates and show form
            jqTemplates.hide();
            jqForm.show();
        }

    }
  
    // Attach class definition to class cache
    gmwk.classes.Contact = Contact;

})(jQuery, window.gmwk);
